package com.eastfair.file.service.util;

import cn.hutool.core.util.StrUtil;
import com.eastfair.core.exception.BizException;

import java.util.*;

/**
 * 文件工具
 *
 * @author dqq
 * @date 2023 /5/11
 */
public class FileTool {

    private static Map<String, String> FILE_TYPE_MAP = new HashMap<>();

    static {
        getAllFileType();
    }

    /**
     * getAllFileType,常见文件头信息
     */
    static void getAllFileType() {
        FILE_TYPE_MAP.put("js", "696b2e71623d696b2e71");
        FILE_TYPE_MAP.put("ps", "252150532D41646F6265");
        FILE_TYPE_MAP.put("gz", "1f8b0800000000000000");
        FILE_TYPE_MAP.put("mf", "4d616e69666573742d56");
        FILE_TYPE_MAP.put("jpg", "ffd8ff");
        FILE_TYPE_MAP.put("jpeg", "ffd8ff");
        FILE_TYPE_MAP.put("png", "89504e47");
        FILE_TYPE_MAP.put("gif", "47494638");
        FILE_TYPE_MAP.put("tif", "49492a00227105008037");
        FILE_TYPE_MAP.put("bmp", "424d");
        FILE_TYPE_MAP.put("dwg", "41433130");
        FILE_TYPE_MAP.put("htm", "3c21646f637479706520");
        FILE_TYPE_MAP.put("css", "48544d4c207b0d0a0942");
        FILE_TYPE_MAP.put("rtf", "7b5c727466315c616e73");
        FILE_TYPE_MAP.put("psd", "38425053000100000000");
        FILE_TYPE_MAP.put("eml", "46726f6d3a203d3f6762");
        FILE_TYPE_MAP.put("doc", "d0cf11e0a1b11ae1");
        FILE_TYPE_MAP.put("docx", "504b0304");
        FILE_TYPE_MAP.put("xls", "d0cf11e0a1b11ae1");
        FILE_TYPE_MAP.put("xlsx", "504b0304");
        FILE_TYPE_MAP.put("vsd", "d0cf11e0a1b11ae1");
        FILE_TYPE_MAP.put("mdb", "5374616E64617264204A");
        // FILE_TYPE_MAP.put("pdf", "255044462d312e350d0a"); // Adobe Acrobat (pdf)
        FILE_TYPE_MAP.put("pdf", "255044462d312e");
        FILE_TYPE_MAP.put("flv", "464c56010500");
        FILE_TYPE_MAP.put("mp4", "000000206674");
        FILE_TYPE_MAP.put("mp3", "494433030000");
        FILE_TYPE_MAP.put("mpg", "000001ba2100");
        FILE_TYPE_MAP.put("wmv", "3026b2758e66");
        FILE_TYPE_MAP.put("wav", "52494646e278");
        FILE_TYPE_MAP.put("avi", "52494646d07d");
        FILE_TYPE_MAP.put("mid", "4d5468640000");
        FILE_TYPE_MAP.put("zip", "504b0304");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("ini", "235468697320");
        FILE_TYPE_MAP.put("jar", "504b03040a00");
        FILE_TYPE_MAP.put("exe", "4d5a90000300");
        FILE_TYPE_MAP.put("jsp", "3c2540207061");
        FILE_TYPE_MAP.put("xml", "3c3f786d6c2076657273");
        FILE_TYPE_MAP.put("sql", "494e5345525420494e54");
        FILE_TYPE_MAP.put("bat", "406563686f206f66660d");
        FILE_TYPE_MAP.put("chm", "49545346030000006000");
        FILE_TYPE_MAP.put("mxp", "04000000010000001300");
        FILE_TYPE_MAP.put("wps", "d0cf11e0a1b11ae10000");
        FILE_TYPE_MAP.put("html", "3c21444f435459504520");
        FILE_TYPE_MAP.put("rmvb", "2e524d46000000120001");
        FILE_TYPE_MAP.put("java", "7061636b616765207765");
        FILE_TYPE_MAP.put("class", "cafebabe0000002e0041");
        FILE_TYPE_MAP.put("torrent", "6431303a637265617465");
        FILE_TYPE_MAP.put("properties", "6c6f67346a2e726f6f74");
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");
        FILE_TYPE_MAP.put("mov", "6D6F6F76");
        FILE_TYPE_MAP.put("wpd", "FF575043");
        FILE_TYPE_MAP.put("pst", "2142444E");
        FILE_TYPE_MAP.put("qdf", "AC9EBD8F");
        FILE_TYPE_MAP.put("pwl", "E3828596");
        FILE_TYPE_MAP.put("ram", "2E7261FD");
    }

    /**
     * 得到上传文件的文件格式编码
     *
     * @param src the src
     * @return string
     */
    public static String getRowFileTypeCode(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        int tempLength = Math.min(src.length, 100);
        for (int i = 0; i < tempLength; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 验证文件扩展名与文件原始格式是否一致
     *
     * @param fileSubFix the file type
     * @param fileBytes  the file bytes
     * @return file type
     */
    public static boolean verifyFileRowSubFix(String fileSubFix, byte[] fileBytes) {
        // 文件格式编码
        String fileTypeCode = getRowFileTypeCode(fileBytes);
        return verifyFileRowSubFix(fileSubFix, fileTypeCode);
    }


    public static boolean verifyFileRowSubFix(String fileSubFix, String fileTypeCode) {
        if (StrUtil.isBlank(fileTypeCode)) {
            throw BizException.wrap(1003, "文件不可为空");
        }
        boolean result = false;
        fileTypeCode = fileTypeCode.toLowerCase(Locale.ENGLISH);
        // 标准文件格式编码
        String standardFileTypeCode = FILE_TYPE_MAP.get(fileSubFix.toLowerCase(Locale.ENGLISH));
        if (StrUtil.isBlank(fileTypeCode) || StrUtil.isBlank(standardFileTypeCode)) {
            return false;
        }
        // 验证文件原始格式和扩展名是否一致
        standardFileTypeCode = standardFileTypeCode.toLowerCase(Locale.ENGLISH);
        fileTypeCode = fileTypeCode.toLowerCase(Locale.ENGLISH);
        if (fileTypeCode.contains(standardFileTypeCode)) {
            return true;
        }
        return result;
    }

    /**
     * 文件头编码获取文件类型
     *
     * @param fileTypeCode the file type code
     * @return the row file type
     */
    public static List<String> getRowFileType(String fileTypeCode) {
        fileTypeCode = fileTypeCode.toLowerCase(Locale.ENGLISH);
        Set<Map.Entry<String, String>> fileTypeEntry = FILE_TYPE_MAP.entrySet();
        List<String> possibleFiletypeList = new ArrayList<>();
        for (Map.Entry<String, String> standardFileTypeEntry: fileTypeEntry) {
            String standardFileTypeCode = standardFileTypeEntry.getValue();
            standardFileTypeCode = standardFileTypeCode.toLowerCase(Locale.ENGLISH);
            if (fileTypeCode.contains(standardFileTypeCode)) {
                possibleFiletypeList.add(standardFileTypeEntry.getKey());
            }
        }
        return possibleFiletypeList;
    }
}